/* 
 * File:   Servidor.cpp
 * Author: max
 * 
 * Created on October 19, 2012, 12:31 AM
 */

#include "Servidor.h"
#include "MotorJuegoFactory.h"
#include "MotorJuegoServicio.h"
#include "MundoServicio.h"
#include "PartidaServicio.h"

using namespace TP::Comunicacion;

Servidor::Servidor(const string& pPuerto, const string& pRutaDirectorioMundos){
    
    // Se inicia  la conexion.
    this->_conexion = new Conexion (pPuerto, this);

    // Se inicia el motor de juego.
    MotorJuegoFactory factory;
    this->_relojJuego = new Reloj (1);  // @todo: ajustar los ticks del reloj de juego.
    this->_motorJuego = factory.crear(this->_relojJuego);
    
    // Instancio los servicios.

    // Instancio y registro el servicio Mundo.
    MundoServicio* mundoSrv = (MundoServicio*) new MundoServicio(pRutaDirectorioMundos);
    mundoSrv->iniciar();
    this->_servicios.push_back(mundoSrv);

    // Instancio y registro el servicio de Mortor de juego.
    MotorJuegoServicio* motorJuegoSrv = (MotorJuegoServicio*) new MotorJuegoServicio();
    motorJuegoSrv->setMotorJuego(this->_motorJuego);
    this->_servicios.push_back(motorJuegoSrv);
    
    // Instancio y registro el servicio de partidas.
    PartidaServicio* partidaSrv = (PartidaServicio*) new PartidaServicio();
    partidaSrv->setMotorJuego(this->_motorJuego);
    partidaSrv->setMundoServicio(mundoSrv);
    partidaSrv->iniciar();
    this->_servicios.push_back(partidaSrv);
}

Servidor::~Servidor() {
    
    // Doy de baja la conexion.
    if (this->_conexion)
        delete this->_conexion;
    
    // Doy de baja los servicios.
    for (int cur = 0; cur < this->_servicios.size(); cur++)
    {
        this->_servicios[cur]->finalizar();
        delete this->_servicios[cur];
    }
    this->_servicios.clear();
    
    delete this->_motorJuego;
    delete this->_relojJuego;
}

void Servidor::Iniciar() throw (Excepcion&){
    try
    {
        this->_conexion->Iniciar();
    }
    catch (Excepcion& pEx)
    {
        pEx.expandirMensaje("No se puede iniciar el sevidor.");
        throw;
    }
}

void Servidor::Finalizar() throw (Excepcion&){
    try
    {
        // Doy de baja las sesiones activas.
        for (vector<Sesion*>::size_type cur = 0; cur < this->_sesiones.size(); cur++)
        {
            try
            {
                this->_sesiones[cur]->Finalizar();
            }
            catch (Excepcion& pEx)
            {
                std::cerr << pEx.what() << endl;
            }
            delete this->_sesiones[cur];
        }
        this->_sesiones.clear();
        
        this->_conexion->Finalizar();
    }
    catch (Excepcion& pEx)
    {
        pEx.expandirMensaje("No se puede finializar el sevidor.");
        throw;
    }
}

void Servidor::eventoNuevaSesion (IEnviante* pEnviante, void* pArg){
    
    Sesion* sesion = (Sesion*) pArg;
    
    try
    {
        if (sesion)
        {
            // Se configuran los manejadores de mensaje de la sesion.
            sesion->agregarManejadorSesionEvento(this);
            
            for (int cur = 0; cur < this->_servicios.size(); cur++)
                sesion->agregarMensajeEntranteManejador((IMensajeEntranteManejador*)this->_servicios[cur]);
            
            // Se debe iniciar la escucha de mensajes de la sesion.
            sesion->Iniciar();
            
            // Se debe registrar la sesion en la lista de sesiones del servidor.
            this->_sesiones.push_back(sesion);
        }
    }
    catch (Excepcion& pEx)
    {
        std::cout << "No se puede manejar la nueva sesion.  " << pEx.what() << endl;
    }
}

void Servidor::eventoErrorComunicacion (IEnviante* pEnviante, const string& pMensaje ){
    cerr << pMensaje << endl;
}

void Servidor::eventoConexionFinalizada (IEnviante* pEnviante, const string& pMensaje){
    cerr << pMensaje << endl;
}

void Servidor::eventoErrorConexionInexistente (IEnviante* pConexion, const string& pMensaje) {
    cerr << pMensaje << endl;
    
}